#include "pluginmanager.h"

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QPluginLoader>
#include <QSettings>

#include "PluginInterface.h"
#include "PluginMessage.h"

PluginManager::PluginManager(QObject *parent) : QObject(parent) {
  initPluginSearchPath();
}

PluginManager::~PluginManager() {
  for (auto i : pluginLoaders)
    i->unload();
  pluginObjects.clear();
  pluginInterfaces.clear();
}

void PluginManager::initPluginSearchPath() {
  QCoreApplication::addLibraryPath("plugins");
}

void PluginManager::loadPlugins() {
  for (auto const &info : QDir("../plugins").entryInfoList(QDir::Files)) {
    auto filePath = info.absoluteFilePath();
    if (!QLibrary::isLibrary(filePath))
      continue;

    auto pluginLoader = new QPluginLoader(filePath);
    if (!pluginLoader)
      continue;

    auto metaData = pluginLoader->metaData();
    auto iid = metaData.value("IID").toString();

    if (iid.isEmpty() || pluginLoaders.contains(iid)) {
      delete pluginLoader;
      continue;
    }

    // 保存loader
    pluginLoaders.insert(iid, pluginLoader);

    // 读取配置，是否使能
    QSettings settings("config.ini", QSettings::IniFormat);
    settings.beginGroup("plugins");
    bool enabled = settings.value(iid).toBool();
    settings.endGroup();

    if (!enabled)
      continue;

    auto pluginObject = pluginLoader->instance();
    auto pluginInterface = qobject_cast<PluginInterface *>(pluginObject);
    if (pluginInterface) {
      pluginObjects.insert(iid, pluginObject);
      pluginInterfaces.insert(iid, pluginInterface);

      connect(pluginObject, SIGNAL(sendMessage(PluginMessage)), this,
              SLOT(receiveMessage(PluginMessage)));
    } else {
      qWarning() << "load plugin " << filePath << " : "
                 << pluginLoader->errorString();
      delete pluginLoader;
    }
  }
}

int PluginManager::count() const { return pluginLoaders.count(); }

PluginMetaData getLoaderMetaData(QPluginLoader *loader) {
  auto jsonData = loader->metaData();

  PluginMetaData pluginMeta;
  pluginMeta.IID = jsonData.value("IID").toString();

  auto metaData = jsonData.value("MetaData").toObject();
  pluginMeta.name = metaData.value("name").toString();
  pluginMeta.version = metaData.value("version").toString();
  pluginMeta.description = metaData.value("description").toString();
  pluginMeta.vendor = metaData.value("vendor").toString();
  pluginMeta.copyright = metaData.value("copyrights").toString();
  pluginMeta.author = metaData.value("author").toString();

  return pluginMeta;
}

QList<PluginMetaData> PluginManager::getPluginMetaData() const {
  QList<PluginMetaData> list;

  for (auto const &i : qAsConst(pluginLoaders))
    list.append(getLoaderMetaData(i));

  return list;
}

PluginMetaData PluginManager::getPluginMetaData(const QString &iid) const {
  if (auto loader = pluginLoaders.value(iid))
    return getLoaderMetaData(loader);

  return PluginMetaData();
}

// 获取指定插件的widget
QWidget *PluginManager::getPluginWidget(const QString &iid) const {
  if (auto interface = pluginInterfaces.value(iid))
    return interface->widget();
  return nullptr;
}

// 查找插件
PluginInterface *PluginManager::findPluginByName(const QString &name) {
  auto iter = pluginInterfaces.constBegin();
  while (iter != pluginInterfaces.constEnd()) {
    auto iid = iter.key();
    if (isLoad(iid)) {
      auto metaData = getPluginMetaData(iid);
      if (metaData.name == name) {
        return iter.value();
      }
    }
    ++iter;
  }

  return nullptr;
}

bool PluginManager::isLoad(const QString &iid) const {
  return pluginLoaders.value(iid)->isLoaded();
}

void PluginManager::receiveMessage(const PluginMessage &message) {
  auto srcPlugin = qobject_cast<PluginInterface *>(sender());
  if (auto pluginInterface = findPluginByName(message.dst)) {
    srcPlugin->receiveMessage(pluginInterface->handleMessage(message));
  }
}
